Metabolite-mediated cell-cell communications (mCCC) analysis using one scRNA-seq data¶

In this tutorial, we apply MEBOCOST on a demo dataset which 200 cells were sampled from a HNSC scRNA-seq data (GSE103322).

Note: since this demo was analyzed by simulated data, the predicted result of communication might looks not biologically meaningful. The goal of this notebook is to show the step-by-step analysis

In [2]:
import os,sys
import scanpy as sc
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns

from mebocost import mebocost

1. Create mebocost object¶

Users can pass data either by adata scanpy object (1.1 reccomended), or by python pandas data frame (1.2)

1.1 get expression and cell annotation data from scanpy object¶

In [2]:
adata = sc.read_h5ad('data/demo/raw_scRNA/demo_HNSC_200cell.h5ad')
## check adata (cells, genes)
print('# of cell: %s, # of gene: %s'%adata.shape)
### make sure your adata cover all genes and all cells
### if not, you may want to load all genes saved in raw by doing:
# adata = adata.raw.copy()
# of cell: 200, # of gene: 18241
create mebocost object¶
In [3]:
## initiate the mebocost object
### import expression data by scanpy adata object
mebo_obj = mebocost.create_obj(
                        adata = adata,
                        ## "Celltype" must be a column name of adata.obs table, otherwise, change it according to your data.
                        group_col = 'celltype',
                        condition_col = None,
                        met_est = 'mebocost',
                        # make sure mebocost.conf file in the same folder of this notebook, otherwise, provide a absolute path.
                        config_path = './mebocost.conf', 
                        exp_mat=None,
                        cell_ann=None,
                        ## make sure you set the right species
                        species='human',
                        met_pred=None,
                        met_enzyme=None,
                        met_sensor=None,
                        met_ann=None,
                        scFEA_ann=None,
                        compass_met_ann=None,
                        compass_rxn_ann=None,
                        cutoff_exp='auto', ## automated cutoff to exclude lowly ranked 25% sensors across all cells
                        cutoff_met='auto', ## automated cutoff to exclude lowly ranked 25% metabolites across all cells
                        cutoff_prop=0.15, ## at lease 10% of cells should be expressed the sensor or present the metabolite in the cell group (specified by group_col)
                        sensor_type='All',
                        thread=8
                        )
[July 24, 2025 10:01:13]: We get expression data with 18241 genes and 200 cells.
[July 24, 2025 10:01:13]: Data Preparation Done in 0.0981 seconds

1.2 get expression and cell annotation from external files (skip if you have done 1.1)¶

Users can provide exp_mat (scRNA-seq gene-by-cell expression matrix) and cell_ann (cell-by-annoatation matrix) from external files, such as .csv, .tsv, and .txt files, to MEBOCOST for mCCC analysis. Please refer to pandas read_csv functions to read those files (read_csv) into Python. In the case that users want to use expression data and meta data from Seurat in R. It is strongly recommended first writing out expression matrix and meta data (cell annotation) from Seurat in R. Once the expression and meta data were saved in your local, those files can be read into Python by pandas and then pass to mebocost as the instructions in following. Please make sure you have total genes in the table, rather than only highly variable genes.

In [8]:
### pass expression data and cell annotation table by pandas data frame
### taking exp_mat and cell_all from the above 
### read expression data from a external file
exp_mat = pd.read_csv(your_exp_data_file)
cell_ann = pd.read_csv(your_cell_ann_data_file)

mebo_obj = mebocost.create_obj(
                        adata = None,
                        ## "Celltype" must be a column name of adata.obs table, otherwise, change it according to your data.
                        group_col = 'Celltype',
                        condition_col = None,
                        met_est = 'mebocost',
                        # make sure mebocost.conf file in the same folder of this notebook, otherwise, provide a absolute path.
                        config_path = './mebocost.conf', 
                        exp_mat=exp_mat,
                        cell_ann=cell_ann,
                        ## make sure you set the right species
                        species='human',
                        met_pred=None,
                        met_enzyme=None,
                        met_sensor=None,
                        met_ann=None,
                        scFEA_ann=None,
                        compass_met_ann=None,
                        compass_rxn_ann=None,
                        cutoff_exp='auto', ## automated cutoff to exclude lowly ranked 25% sensors across all cells
                        cutoff_met='auto', ## automated cutoff to exclude lowly ranked 25% metabolites across all cells
                        cutoff_prop=0.15, ## at lease 10% of cells should be expressed the sensor or present the metabolite in the cell group (specified by group_col)
                        sensor_type='All',
                        thread=8
                        )

2.1 Aggregating metabolite enzyme expression [Optional]¶

  • Note: this estimation have been already incoperated in mebo_obj.infer_commu, so only run this step separately if you just want to aggregate enzyme expression for metabolites and stop from doing further analysis.
  • In [4]:
    ## 【optional】only aggregate metabolite enzyme expression for cells 
    ## this estimation actually included in infer_commu function, if you want 
    ## two steps include loading config and running estimator
    mebo_obj._load_config_()
    mebo_obj.estimator()
    
    [July 23, 2025 23:09:14]: Load config and read data based on given species [human].
    [July 23, 2025 23:09:14]: Estimtate metabolite enzyme expression using mebocost
    
    In [5]:
    ## check the aggregated enzyme expression for metabolites
    met_mat = pd.DataFrame(mebo_obj.met_mat.toarray(),
                          index = mebo_obj.met_mat_indexer,
                          columns = mebo_obj.met_mat_columns)
    ## print head
    met_mat.head()
    
    Out[5]:
    HNSCC5_p14_HNSCC5_P14_LN_H02 HNSCC_17_P10_C11_S227_comb HNSCC6_p15_HNSCC6_P15_LN_D05 HNSCC25_P2_A10_S10_comb HNSCC16_P4_HNSCC16_P4_B11 HNSCC18_P7_F06_S162_comb HNSCC25_P4_E04_S244_comb HNSCC20_P5_pri_A01_S1_comb HN28_P5_F10_S262_comb HNSCC17_P13_E12_S348_comb ... HNSCC6_p16_HNSCC6_P16_B03 HNSCC8_1ant_HNSCC8_1ant_A06 HNSCC26_P24_H06_S378_comb HNSCC16_P2_F09_S69_comb HNSCC6_p14_hnscc6_p14_D12 HNSCC18_P2_F02_S158_comb HNSCC16_P12_HNSCC16_P12_G10 HNSCC16_P14_HNSCC16_P14_H10 HNSCC6_p16_HNSCC6_P16_E07 HNSCC28_P13_A12_S204_comb
    HMDB0003450 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 ... 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
    HMDB0003948 0.255695 0.303540 0.267465 0.000000 0.413994 0.146958 0.0 0.327930 0.210271 0.000835 ... 0.225085 0.183810 0.359314 0.002629 0.433498 0.413497 0.001104 0.004354 0.202068 0.313849
    HMDB0003712 0.204556 0.242832 0.302952 0.000000 0.331195 0.117567 0.0 0.342155 0.235718 0.297141 ... 0.180068 0.147048 0.473624 0.226876 0.421987 0.330798 0.000883 0.003483 0.375619 0.251079
    HMDB0003945 0.227284 0.366798 0.383685 0.222933 0.447552 0.441383 0.0 0.480210 0.296026 0.000742 ... 0.200076 0.163386 0.319390 0.249946 0.539379 0.367553 0.328898 0.003870 0.179616 0.278977
    HMDB0003949 0.255695 0.303540 0.267465 0.000000 0.413994 0.146958 0.0 0.327930 0.210271 0.000835 ... 0.225085 0.183810 0.359314 0.002629 0.433498 0.413497 0.001104 0.004354 0.202068 0.313849

    5 rows × 200 columns

    2.2 communication inference¶

    In [14]:
    ## metabolic communication inference, this step takes a while
    commu_res = mebo_obj.infer_commu(
                                    n_shuffle=1000,
                                    seed=12345, 
                                    Return=True, 
                                    thread=None,
                                    save_permuation=False,
                                    min_cell_number = 10,
                                    pval_method='permutation_test_fdr',
                                    pval_cutoff=0.05
                                )
    
    In [12]:
    print('Number of significant mCCC detected by enzyme and sensor co-expression: ', commu_res.shape[0])
    
    Number of significant mCCC detected by enzyme and sensor co-expression:  244
    

    2.3 save mebocost object and reload object¶

    MEBOCOST object can be saved as a pickle file which is a python-based file format using less disk space¶

    save¶
    In [13]:
    # ### save 
    mebocost.save_obj(obj = mebo_obj, path = './demo_HNSC_200cell_commu.pk')
    
    reload¶
    In [3]:
    ## re-load the previous object when you need it
    mebo_obj = mebocost.load_obj('./demo_HNSC_200cell_commu.pk')
    
    [July 25, 2025 10:50:01]: Data Preparation Done in 0.0007 seconds
    
    In [4]:
    ## check cutoff
    print('sensor_exp cutoff: %s'%mebo_obj.cutoff_exp)
    print('metabolite_agg_enzyme cutoff: %s'%mebo_obj.cutoff_met)
    
    sensor_exp cutoff: 0.014082301408052444
    metabolite_agg_enzyme cutoff: 0.03198429848998785
    

    Several option steps offered to improve the mCCC analysis¶

    2.4 Integrate COMPASS to constrain mCCC analysis by efflux and influx rates [Optional]¶

    This can be done by running COMPASS, a tool for compute flux rates, using single-cell data. Please install the COMPASS following the instructions at https://yoseflab.github.io/Compass/install.html

    This is an optional step for a further constaint. As showed in the benchmarking analysis using spatial transcriptiomics, our baseline model also performed well, although incoperating flux results can improve it in some cases. Please refer to Supplementary Fig 14 in our paper for more details (https://doi.org/10.1093/nar/gkaf569).

    In [5]:
    ### Running COMPASS for each cell type by the average gene expression
    ### output average gene expression
    avg_exp = sc.get.aggregate(adata, by = 'celltype', func='mean')
    avg_exp = pd.DataFrame(avg_exp.layers['mean'], index = avg_exp.obs_names, columns = avg_exp.var_names).T
    # ## do un log since COMPASS will take log in the algorithm
    avg_exp = avg_exp.apply(lambda col: np.exp(col)-1)
    avg_exp.to_csv('avg_exp_mat.tsv', sep = '\t')
    

    Running the COMPASS using avg_exp_mat.tsv, and get secretion.tsv and uptake.tsv results

    Example command line in bash:

    exptsv_path=your_folder/avg_exp_mat.tsv
    species=homo_sapiens
    output_path=your_folder/compass_res
    temp_path=your_folder/compass_res_tmp
    core=8
    compass=/root/miniconda3/bin/compass
    
    echo '++++ run compass'
    ## since it is cell type level analysis, so lambda set to 0
    $compass --data $exptsv_path --num-thread $core --species $species --output-dir $output_path --temp-dir $temp_path --calc-metabolites --lambda 0
    echo 'Finished'
    

    Update the commu_res in the mebocost object based on secretion.tsv and uptake.tsv in COMPASS result folder

    In [7]:
    ## apply constraint on compass flux result
    updated_res = mebo_obj._ConstrainCompassFlux_(compass_folder='../draft/data/demo/compass_res/',
                                        efflux_cut='auto',
                                        influx_cut='auto',
                                        inplace=False)
    
    efflux_cut: 12.825990686525856
    influx_cut: 2.2878083908133204
    
    In [8]:
    ## update to the object
    mebo_obj.commu_res = updated_res
    print('Number of mCCC detected by further flux contrains', updated_res.shape[0])
    
    Number of mCCC detected by further flux contrains 152
    

    2.5 Apply mCCC constraints by efflux and influx rates computed from other any software of interest [Optional]¶

    This is useful when you have other FBA tools to compute influx and efflux rates for each metabolites. Those tools can be e.g. scFEA, scFBA, etc. However, we need users to prepare a efflux matrix and influx data frame, where rows = metabolite names, columns = cell type names. With those two data frames, users can use the following function to constrain the mCCC result.

    In [ ]:
    ## provide results of influx mat and efflux mat from your tool 
    influx_mat = ...
    efflux_mat = ...
    
    update_commu_res = mebo_obj._ConstrainFluxFromAnyTool_(
                               influx_mat=influx_mat,
                               efflux_mat=efflux_mat,
                               norm = True, inplace = False
                              )
    mebo_obj.commu_res = update_commu_res
    

    [Optinal] 2.6 Examing whether the mCCC were confounded by highly abundant metabolites in the blood. Use this in Cautious.¶

    We have tested the correlation between mCCC scores and blood metabolite concentrations across multiple samples. Generally, we did NOT observe a very strong confounding from blood metabolites to MEBOCOST mCCC scores. Nevertheless, we provide users with a function to examine such a confounding in their own data and offer correction by fitting a linear regression model between mCCC score and metabolite level in blood. The corrected mCCC score will be calculated by subtracting the predicted values from the original mCCC score in the regression model. To do this, simply run the following function. The met_cont_file is a required data, which should be a table with two columns corresponding to metabolite name and concentration, formatted as tab-delimited and without a header.

    In [6]:
    corrected_commu_res = mebo_obj._blood_correct_test_(met_cont_file='data/mebocost_db/common/hmdb_blood_metabolite_concentration.tsv',
                                    commu_score_col='Commu_Score',
                                    title='',
                                    show_plot=False,
                                    pdf=False)
    ## the Corrected_Commu_Score column is the corrected mCCC score. Update the commu_score table to the object, if the confounding is strong.
    # mebo_obj.commu_res = corrected_commu_res.copy()
    

    2.7 Now explore the mCCC result by Interactive Visualization Fuction¶

    To provide a user-friendly visualization of mebocost result, especially for those datasets with large number of communication events, notebook interactive view shed lights in. We developed the Jupyter interactive widgets to mimic webpage. NOTE: this function can only be used in Jupyter notebook

    In [7]:
    ## here, users can click and plot figures
    
    ## interactive view module mimic a website but all go with our default parameters
    mebo_obj.communication_in_notebook(pval_method='permutation_test_fdr',
                                        pval_cutoff=0.05,
                                        comm_score_col='Commu_Score',
                                        comm_score_cutoff=None,
                                        cutoff_prop=None)
    

    Select and Click button to visulize

    VBox(children=(RadioButtons(description='Logic', options=('and', 'or'), value='and'), HBox(children=(SelectMul…

    2.8 You can also visualize mCCC result by generating figure manually¶

    summary of the number of communication events¶

    In [9]:
    ## sender and receiver event number
    mebo_obj.eventnum_bar(
                        sender_focus=[],
                        metabolite_focus=[],
                        sensor_focus=[],
                        receiver_focus=[],
                        xorder=[],
                        and_or='and',
                        pval_method='permutation_test_fdr',
                        pval_cutoff=0.05,
                        comm_score_col='Commu_Score',
                        comm_score_cutoff = 0,
                        cutoff_prop = 0.15,
                        figsize=(6,4.5),
                        save=None,
                        show_plot=True,
                        show_num = True,
                        include=['sender-receiver'],
                        group_by_cell=True,
                        colorcmap='tab20',
                        return_fig=False
                    )
    
    No description has been provided for this image

    summay of communication in cell-to-cell network¶

    In [10]:
    ## circle plot to show communications between cell groups
    mebo_obj.commu_network_plot(
                        sender_focus=[],
                        metabolite_focus=[],
                        sensor_focus=[],
                        receiver_focus=[],
                        and_or='and',
                        pval_method='permutation_test_fdr',
                        pval_cutoff=0.05,
                        node_cmap='tab20',
                        figsize=(6,3),
                        line_cmap='bwr',
                        line_color_vmin=None,
                        line_color_vmax=None,
                        linewidth_norm=(0.2, 1),
                        linewidth_value_range = None,
                        node_size_norm=(50, 200),
                        node_value_range = None,
                        adjust_text_pos_node=True,
                        node_text_hidden = False,
                        node_text_font=10,
                        save=None,
                        show_plot=True,
                        comm_score_col='Commu_Score',
                        comm_score_cutoff=0,
                        text_outline=True,
                        return_fig=False
                    )
    
    ### the "overall score" represent the sum of -log10(FDR) of detected metabolite-sensor communications between a pair of cell types
    
    [July 25, 2025 10:51:49]: show communication in cells by network plot
    
    No description has been provided for this image

    Showing the communication between sender and receiver in a dot plot¶

    In [11]:
    ### dot plot to show the number of communications between cells
    
    mebo_obj.count_dot_plot(
                            pval_method='permutation_test_fdr',
                            pval_cutoff=0.05,
                            cmap='bwr',
                            figsize=(10,6),
                            save=None,
                            dot_size_norm =(20, 200),
                            dot_value_range = None,
                            dot_color_vmin=None,
                            dot_color_vmax=None,
                            show_plot=True,
                            comm_score_col='Commu_Score',
                            comm_score_cutoff=0,
                            dendrogram_cluster=True,
                            sender_order=[],
                            receiver_order=[],
                            return_fig = False
                        )
    
    [July 25, 2025 10:51:53]: plot dot plot to show communication in cell type level
    
    No description has been provided for this image

    Showing the detailed communications (sender-receiver vs metabolite-sensor) in a dot map¶

    In [12]:
    ## Malignant cell was focused, use receiver_focus=[] to include all cell types
    mebo_obj.commu_dotmap(
                    sender_focus=[],
                    metabolite_focus=[],
                    sensor_focus=[],
                    receiver_focus=[],
                    and_or='and',
                    pval_method='permutation_test_fdr',
                    pval_cutoff=0.05,
                    figsize='auto',
                    cmap='bwr',
                    cmap_vmin = None,
                    cmap_vmax = None,
                    cellpair_order=[],
                    met_sensor_order=[],
                    dot_size_norm=(10, 150),
                    save=None,
                    show_plot=True,
                    comm_score_col='Commu_Score',
                    comm_score_range = None,
                    comm_score_cutoff=0,
                    swap_axis = False,
                    return_fig = False
                    )
    
    [July 25, 2025 10:51:57]: plot heatmap for significant result
    
    No description has been provided for this image

    Visualization of the communication flow from sender metabolite to sensor in receiver¶

    In [13]:
    ## Malignant cell was focused, use receiver_focus=[] to include all cell types
    mebo_obj.FlowPlot(
                    pval_method='permutation_test_fdr',
                    pval_cutoff=0.05,
                    ## set to focus on mCCC of interest
                    sender_focus=[],
                    metabolite_focus=[],
                    sensor_focus=[],
                    receiver_focus=[],
                    remove_unrelevant = False,
                    and_or='and',
                    node_label_size=8,
                    node_alpha=0.6,
                    figsize='auto',
                    node_cmap='Set1',
                    line_cmap='bwr',
                    line_cmap_vmin = None,
                    line_cmap_vmax = None,
                    node_size_norm=(20, 150),
                    node_value_range = None,
                    linewidth_norm=(0.5, 5),
                    linewidth_value_range = None,
                    save=None,
                    show_plot=True,
                    comm_score_col='Commu_Score',
                    comm_score_cutoff=0,
                    text_outline=False,
                    return_fig = False
                )
    
    [July 25, 2025 10:52:03]: plot flow plot to show the communications from Sender -> Metabolite -> Sensor -> Receiver
    
    No description has been provided for this image

    Visualization of the aggregated enzyme expression for metabolite or sensor expression in cell groups¶

    In [14]:
    ## violin plot to show the aggregated metabolite enzymes of informative metabolties in communication
    ### here we show five significant metabolites,
    ### users can pass several metabolites of interest by provide a list
    commu_df = mebo_obj.commu_res.copy()
    good_met = commu_df[(commu_df['permutation_test_fdr']<0.05)]['Metabolite_Name'].sort_values().unique()
    
    mebo_obj.violin_plot(
                        sensor_or_met=good_met[:5], ## only top 5 as example
                        cell_focus=[],
                        cell_order = [],
                        row_zscore = False,
                        cmap=None,
                        vmin=None,
                        vmax=None,
                        figsize='auto',
                        cbar_title='',
                        save=None,
                        show_plot=True
                        )
    
    [July 25, 2025 10:52:34]: Warnings: no sensors to plot
    [July 25, 2025 10:52:34]: Find metabolites ['Acetic acid', '20-Hydroxy-leukotriene B4', '27-Hydroxycholesterol', 'ADP', 'Adenosine triphosphate'] to plot violin
    
    No description has been provided for this image
    In [15]:
    ## violin plot to show the expression of informative sensors in communication
    
    good_sensor = commu_df[(commu_df['permutation_test_fdr']<0.05)]['Sensor'].sort_values().unique()
    
    mebo_obj.violin_plot(
                        sensor_or_met=good_sensor[:5],## only top 5 as example
                        cell_focus=[],
                        cell_order = [],
                        row_zscore = False,
                        cmap=None,
                        vmin=None,
                        vmax=None,
                        figsize='auto',
                        cbar_title='',
                        save=None,
                        show_plot=True
                        )
    
    [July 25, 2025 10:52:35]: Find genes Index(['CYSLTR1', 'AQP3', 'FDPS', 'FFAR2', 'ANXA2'], dtype='object') to plot violin
    
    No description has been provided for this image
    [July 25, 2025 10:52:36]: Warnings: no metabolites to plot
    

    2.9 extract data and save figures¶

    extract communication and write to a table:¶

    In [18]:
    ### the updated and tidy communication result is in object, can be retreved by:
    commu_res = mebo_obj.commu_res.copy()
    ## filter by FDR less than 0.05
    commu_res = commu_res[commu_res['permutation_test_fdr']<0.05]
    ## write to tsv file
    commu_res.to_csv('communication_result.tsv', sep = '\t', index = None)
    

    save figures¶

    Users can save figures by either providing by parameter 'save' for each plotting function, or save figure separately by hand, in this case, users need to set 'return_fig = True'

    Method 1: a example for providing filename by parameter¶
    In [28]:
    mebo_obj.eventnum_bar(
                        sender_focus=[],
                        metabolite_focus=[],
                        sensor_focus=[],
                        receiver_focus=[],
                        and_or='and',
                        pval_method='permutation_test_fdr',
                        pval_cutoff=0.05,
                        comm_score_col='Commu_Score',
                        comm_score_cutoff = 0,
                        cutoff_prop = 0.15,
                        figsize='auto',
                        ## Note that filename passed by save parameter:
                        save='mebocost_eventnum.pdf',
                        show_plot=False,
                        show_num = True,
                        include=['sender-receiver'],
                        group_by_cell=True,
                        colorcmap='tab20',
                        return_fig=False
                    )
    
    Method 2: a example for saving figures separately¶
    In [30]:
    fig = mebo_obj.eventnum_bar(
                        sender_focus=[],
                        metabolite_focus=[],
                        sensor_focus=[],
                        receiver_focus=[],
                        and_or='and',
                        pval_method='permutation_test_fdr',
                        pval_cutoff=0.05,
                        comm_score_col='Commu_Score',
                        comm_score_cutoff = 0,
                        cutoff_prop = 0.15,
                        figsize='auto',
                        save=None,
                        show_plot=False,
                        show_num = True,
                        include=['sender-receiver'],
                        group_by_cell=True,
                        colorcmap='tab20',
                        return_fig=True
                    )
    ## save figure to pdf
    fig.savefig('mebocost_eventnum.pdf')
    ## save to png
    fig.savefig('mebocost_eventnum.png')
    ## save to svg
    fig.savefig('mebocost_eventnum.svg')
    

    3 Change parameters to re-loaded object¶

    change or revise config file

    If you changed the workspace compared to the one where you generated this object, or you want to change configure files (mebocost.conf), you may want to reset the path of the configure file, you can check the path of configure file in the current re-loaded object by:

    In [31]:
    ### If you changed the workspace compared to the one where you generated this object, 
    ### or you want to change configure files (mebocost.conf),
    ### you may want to reset the path of the configure file, 
    ### you can check the path of configure file in the current re-loaded object by:
    print('config file path in the object:', mebo_obj.config_path)
    
    #### if you do need to change, revise the mebocost.conf file first. 
    ### If done, pass the path to mebocost:
    
    mebo_obj.config_path = './mebocost.conf'
    
    #### then, re-load config files
    
    mebo_obj._load_config_()
    
    config file path in the object: ./mebocost.conf
    [May 15, 2024 14:42:36]: Load config and read data based on given species [human].
    

    If you want to change parameters such as cutoff of sensor expression or metabolite aggregated enzyme expression¶

    In [34]:
    # ## if users want to adjust some parameters regarding cutoff of expression 
    # ## and proportion of cells expressed to focus on highly confident ones,
    
    # ## we save the original result in variable of original_result, 
    # ## so additional filtering can be done on this data frame
    
    # ## the cutoff of sensor expression and metabolite abundance 
    # ## should really dependent onusers dataset
    
    # ## exp_prop and met_prop have been saved in the mebocost object, 
    # ## you can retreve by mebo_obj.exp_prop and mebo_obj.met_prop
    # ## you also can re-calculate by changing the cutoff:
    
    mebo_obj._check_aboundance_(cutoff_exp = 0.1,
                                cutoff_met = 0.1)
    
    
    ## you can pass the exp_prop and met_prop to the function and 
    ## filter out bad communications under the cutoff
    ## here is the example to use newly calculated exp_prop and met_prop
    ## if you want to use previously calculated in mebocost object, 
    ## you can replace met_prop by mebo_obj.met_prop, same for exp_prop
    ## cutoff_prop here means the faction of cells in the cell group expressing the senser
    ## or having the abundant of metabolite
    commu_res_new = mebo_obj._filter_lowly_aboundant_(pvalue_res = mebo_obj.original_result.copy(),
                                                        cutoff_prop = 0.25,
                                                        met_prop = mebo_obj.met_prop,
                                                        exp_prop = mebo_obj.exp_prop,
                                                        min_cell_number = 10,
                                                        return_signi_only = True
                                                     )
    
    ## update your commu_res in mebocost object, 
    ## so that the object can used to generate figure based on the updated data
    mebo_obj.commu_res = commu_res_new.copy()
    
    # ## change such parameters to narrow down to highly confident communications if you got a big number of communications in your data 
    
    
    ## constrain by eflux and influx if you have COMPASS result
    updated_res = mebo_obj._ConstrainCompassFlux_(compass_folder='data/demo/compass_res/',
                                        efflux_cut='auto',
                                        influx_cut='auto',
                                        inplace=False)
    mebo_obj.commu_res = updated_res.copy()
    print('Number of mCCC detected by the new parameters: %s'%mebo_obj.commu_res.shape[0])
    
    [May 15, 2024 14:44:05]: Calculating metabolite aggregated enzyme and sensor expression in cell groups
    [May 15, 2024 14:44:05]: cutoff for sensor expression, cutoff=0.1
    [May 15, 2024 14:44:05]: cutoff for metabolite aggregated enzyme, cutoff=0.1
    [May 15, 2024 14:44:05]: cutoff_exp: 0.1
    [May 15, 2024 14:44:06]: cutoff_metabolite: 0.1
    [May 15, 2024 14:44:07]: Set p value and fdr to 1 if sensor or metaboltie expressed cell proportion less than 0.25
    efflux_cut: 10.105265015312568
    influx_cut: 2.352030916167703
    Number of mCCC detected by the new parameters: 145
    
    In [ ]: